home *** CD-ROM | disk | FTP | other *** search
/ Monster Media 1996 #15 / Monster Media Number 15 (Monster Media)(July 1996).ISO / math / alged34.zip / ALGEDSRC.ZIP / ALGFILE.C < prev    next >
C/C++ Source or Header  |  1996-06-06  |  14KB  |  525 lines

  1. /*--------------------------------------------------------------------
  2.    Alged:  Algebra Editor    henckel@vnet.ibm.com
  3.  
  4.    Copyright (c) 1994 John Henckel
  5.    Permission to use, copy, modify, distribute and sell this software
  6.    and its documentation for any purpose is hereby granted without fee,
  7.    provided that the above copyright notice appear in all copies.
  8. */
  9. #include "alged.h"
  10. /*%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
  11.  
  12.     The following functions relate to reading and writing data files.
  13. */
  14. #define push(tt) do { tt->next = tos; tos = tt; } while(0)
  15. #define pop(tt) do { tt=tos; \
  16.    if (!tos) printf(msg[1]); else tos=tos->next; } while(0)
  17. #define pushr(tt) do { tt->next = r; r = tt; } while(0)
  18. #define popr(tt) do { tt=r; \
  19.    if (!r) printf(msg[2]); else r=r->next; } while(0)
  20.  
  21.            /*   = f + - * / ^ V N ? ( ) ,   used by infix read/write */
  22. int wpr[10] = { 0,8,2,2,4,4,6,8,8,8 };
  23. int rpr[15] = { 0,1,2,2,4,4,6,8,8,8,1,2,2 };
  24.  
  25. /* start-paren and end-paren, these are used as pseudo tokens. */
  26. #define SPA 10
  27. #define EPA 11
  28. #define CMA 12
  29. #define coper "=()+-*/^,"
  30. #define numer "0123456789."
  31. static char txt[2000];
  32. char gdriver[80] = "";        // these three lines are exported to algraph.c
  33. int gmode,pst,psz;
  34. double lightx=1,lighty=3,lightz=2;  // light source location
  35. static int stoe=0;        // see note in writetree
  36.  
  37. /*-----------------------------------------------------------------
  38.    parse option
  39. */
  40. void parse_option(FILE *f, char *b) {
  41.   int i=0; double t;
  42.   switch (*b) {
  43.     case 's': fscanf(f,"%d",&bold1); break;
  44.     case 'i': fscanf(f,"%d",&bold2); break;
  45.     case 'c': fscanf(f,"%d",&norm); break;
  46.     case 'm': fscanf(f,"%d",&mcolor); break;
  47.     case 'e': fscanf(f,"%d",&sigdig); break;
  48.     case 'd': fscanf(f,"%lg",&maxrat); break;
  49.     case 'p': fscanf(f,"%d",&maxpow); break;
  50.     case 'a': fscanf(f,"%d",&ch8); break;
  51.     case 'v': fscanf(f,"%d",&i); directvideo=(i>0); break;
  52.     case 'y': fscanf(f,"%d",&yadj); break;
  53.     case '.': fscanf(f,"%d",&point); break;
  54.     case 'l': fscanf(f,"%3s",lang); break;
  55.     case 'f': fscanf(f,"%d",&postfix); break;
  56.     case 'g': fscanf(f,"%s %d %d %d",gdriver,&gmode,&pst,&psz); break;
  57.     case 'r': fscanf(f,"%lg %lg %lg",&lightx,&lighty,&lightz);
  58.               t = hypot(lightx,hypot(lighty,lightz));
  59.               if (t < 1E-20) lighty=1;
  60.               else { lightx/=t; lighty/=t; lightz/=t; }
  61.               break;
  62.   }
  63. }
  64. /*-----------------------------------------------------------------
  65.    get one token from the file
  66.    if nn=1 then negative signs are treated as operators.
  67. */
  68. node *gettoken(FILE *f,int nn) {
  69.   int c,i;
  70.   static char buf[80];
  71.   double t;
  72.   node *p;
  73.   do {
  74.     c = fgetc(f);
  75.     if (c==';') do { c=fgetc(f); } while (c>0 && c!=10);
  76.     if (c=='?') {
  77.       fscanf(f,"%s",buf);
  78.       parse_option(f,buf);
  79.       c=0;
  80.     }
  81.     else if (c=='"') {
  82.       i = strlen(txt);
  83. /*      txt[i]=c;
  84.       fgets(txt+i+1,sizeof txt-i-2,f); */
  85.       fgets(txt+i,sizeof txt-i-1,f);
  86.       strcat(txt,"\r"); c=0;
  87.     }
  88.     else if (c=='@') {
  89.       fscanf(f,"%s",buf);
  90.       p = newvar(buf);
  91.       p->kind = FUN;
  92.       return p;
  93.     }
  94.     else if (c<0) return NULL;    /* EOF */
  95.   } while (c<=' ');
  96.   if (c=='*') return newoper(MUL);
  97.   if (c=='/') return newoper(DIV);
  98.   if (c=='^') return newoper(EXP);
  99.   if (c==')') return newoper(EPA);
  100.   if (c=='(') return newoper(SPA);
  101.   if (c=='=') return newoper(EQU);
  102.   if (c=='+') return newoper(ADD);
  103.   if (c==',') return newoper(CMA);
  104.   if (c=='-') {
  105.     if (nn) return newoper(SUB);
  106.     c = fgetc(f);               /* look ahead */
  107.     ungetc(c,f);
  108.     if (strchr(numer,c)) { t=0;
  109.       fscanf(f,"%lg",&t);
  110.       return newnum(-t);
  111.     }
  112.     else {
  113.       printf(msg[34]); pause;     // unary minus warning
  114.       return newnum(-1);
  115.     }
  116.   }
  117.   if (strchr(numer,c)) {
  118.     ungetc(c,f);
  119.     fscanf(f,"%lg",&t);
  120.     return newnum(t);
  121.   }
  122.   i = 0;
  123.   buf[i++] = c;
  124.   while (i<25) {
  125.     c=fgetc(f);
  126.     if (strchr(coper,c)) {
  127.       if (c=='(') {
  128.         p=newnode();
  129.         p->kind=FUN;
  130.         buf[i]=0;
  131.         strcpy(p->name,buf);
  132.         p->nump = 1;
  133.         return p;
  134.       }
  135.       ungetc(c,f); break;
  136.     }
  137.     if (c<=' ') break;
  138.     buf[i++] = c;
  139.   }
  140.   buf[i]=0;
  141.   if (!strcmp(buf,"e"))     return newnum(M_E);
  142.   if (!strcmp(buf,"pi"))    return newnum(M_PI);
  143.   return newvar(buf);
  144. }
  145. /*-----------------------------------------------------------------
  146.    load infix expression
  147. */
  148. node *loadinfix(char *filename) {
  149.   FILE *f;
  150.   node *tos,*p,*r,*t;
  151.   int i,y;              /* y == previous was a num or var */
  152.  
  153.   f = fopen(filename,"r");
  154.   if (f==NULL) {
  155.     printf(msg[3],filename);
  156.     pause;
  157.     return NULL;
  158.   }
  159.   tos = r = NULL;
  160.   *txt = y = 0;
  161.   p = gettoken(f,y);
  162.   while (p) {
  163.     if (*txt && p->kind<=NUM) {
  164.       p->msg = malloc(strlen(txt)+1);
  165.       strcpy(p->msg,txt);
  166.       *txt = 0;
  167.     }
  168.     if (y && (rpr[p->kind]==8 || rpr[p->kind]==1))  /* NEW EXPRESSION */
  169.       while (r) {                                   /* REDUCE ALL */
  170.         popr(t);
  171.         if (t->kind > EXP) continue;
  172.         t->nump = 2;
  173.         pop(t->rt);
  174.         pop(t->lf);
  175.         if (t->lf->msg) {
  176.           t->msg = t->lf->msg;
  177.           t->lf->msg = NULL;
  178.         }
  179.         push(t);
  180.       }
  181.     if (rpr[p->kind]==1) {         /* FUNC or StartPAREN */
  182.       pushr(p);
  183.       y=0;
  184.     }
  185.     else if (rpr[p->kind]==8) {           /* VAR and NUM */
  186.       push(p);
  187.       y=1;
  188.     }
  189.     else if (r && rpr[p->kind] <= rpr[r->kind] &&
  190.                                   p->kind != EXP) {   /* REDUCE */
  191.       popr(t);
  192.       if (t->kind > EXP) continue;
  193.       t->nump = 2;
  194.       pop(t->rt);
  195.       pop(t->lf);
  196.       if (t->lf->msg) {
  197.         t->msg = t->lf->msg;
  198.         t->lf->msg = NULL;
  199.       }
  200.       push(t);
  201.       continue;    /* don't get more input */
  202.     }
  203.     else if (r && r->kind==FUN && p->kind==CMA) {    /* COMMA */
  204.       r->nump++;
  205.       freenode(p);
  206.       y=0;
  207.     }
  208.     else if (r && r->kind==FUN && p->kind==EPA) {   /* END OF FUNCTION */
  209.       popr(t);
  210.       if (t->nump>MAXP) t->nump = MAXP;
  211.       for (i=t->nump; i--; ) pop(t->parm[i]);
  212.       if (t->lf->msg) {
  213.         t->msg = t->lf->msg;
  214.         t->lf->msg = NULL;
  215.       }
  216.       push(t);
  217.       freenode(p);   /* free close paren */
  218.       y=1;
  219.     }
  220.     else if (r && r->kind==SPA && p->kind==EPA) {   /* MATCH PARENS */
  221.       popr(t);
  222.       freenode(t);
  223.       freenode(p);
  224.       y=1;
  225.     }
  226.     else {
  227.       if (p->kind > EXP) {
  228.         printf(msg[4]);
  229.         pause;
  230.       }
  231.       else pushr(p);                        /* SHIFT */
  232.       y=0;
  233.     }
  234.     p = gettoken(f,y);
  235.   }
  236.   while (r) {                       /* REDUCE all remaining oper */
  237.     popr(t);
  238.     if (t->kind > EXP) continue;
  239.     t->nump = 2;
  240.     pop(t->rt);
  241.     pop(t->lf);
  242.     if (t->lf->msg) {
  243.       t->msg = t->lf->msg;
  244.       t->lf->msg = NULL;
  245.     }
  246.     push(t);
  247.   }
  248.   fclose(f);
  249.   return tos;
  250. }
  251.  
  252. /*--------------------------------------------------------------------
  253.    load a sample expression
  254. */
  255. node *load(char *filename) {
  256.   FILE *f;
  257.   static char tok[80];
  258.   node *tos,*p;
  259.   int i;
  260.   double t;
  261.  
  262.   f = fopen(filename,"r");
  263.   if (f==NULL) {
  264.     printf(msg[5],filename);
  265.     pause;
  266.     return NULL;
  267.   }
  268.   tos = NULL;
  269.   *txt = 0;
  270.   while (1) {
  271.     if (1 != fscanf(f,"%24s",tok)) break;
  272.     if (tok[0]==';') {
  273.       fgets(tok,sizeof tok,f);
  274.       continue;
  275.     }
  276.     if (tok[0]=='"') {
  277.       strcat(txt,tok+1);   i=strlen(txt);
  278.       fgets(txt+i,sizeof txt-i-2,f);
  279.       strcat(txt,"\r");
  280.       continue;
  281.     }
  282.     if (*tok=='?') {            /* --- Options ---- */
  283.       parse_option(f,tok+1);
  284.       continue;
  285.     }
  286.     if (*tok=='*') {        /* ------------------ */
  287.       p = newoper(MUL);
  288.       pop(p->rt);
  289.       pop(p->lf);
  290.       push(p);
  291.     }
  292.     else if (*tok=='=') {        /* ------------------ */
  293.       p = newoper(EQU);
  294.       pop(p->rt);
  295.       pop(p->lf);
  296.       push(p);
  297.     }
  298.     else if (*tok=='+') {        /* ------------------ */
  299.       p = newoper(ADD);
  300.       pop(p->rt);
  301.       pop(p->lf);
  302.       push(p);
  303.     }
  304.     else if (*tok=='-' && !tok[1]) { /* ------------------ */
  305.       p = newoper(SUB);
  306.       pop(p->rt);
  307.       pop(p->lf);
  308.       push(p);
  309.     }
  310.     else if (*tok=='/') {         /* ------------------ */
  311.       p = newoper(DIV);
  312.       pop(p->rt);
  313.       pop(p->lf);
  314.       push(p);
  315.     }
  316.     else if (*tok=='^') {         /* ------------------ */
  317.       p = newoper(EXP);
  318.       pop(p->rt);
  319.       pop(p->lf);
  320.       push(p);
  321.     }
  322.     else if (*tok=='@') {         /* ------------------ */
  323.       pop(p);
  324.       if (p->kind != NUM) printf(msg[6],tok);
  325.       strcpy(p->name,tok+1);
  326.       p->kind = FUN;
  327.       p->nump = p->value;
  328.       if (p->nump < 0) printf(msg[7],tok);
  329.       if (p->nump >= MAXP) printf(msg[8],tok);
  330.       for (i=p->nump; i--; ) {
  331.         pop(p->parm[i]);
  332.       }
  333.       push(p);
  334.     }
  335.     else if (!strcmp(tok,"e")) {
  336.       p = newnum(M_E);
  337.       push(p);
  338.     }
  339.     else if (!strcmp(tok,"pi")) {
  340.       p = newnum(M_PI);
  341.       push(p);
  342.     }
  343.     else if (*tok<='9' && *tok>='0' || *tok=='.' || *tok=='-') {
  344.       sscanf(tok,"%lg",&t);
  345.       p = newnum(t);
  346.       push(p);
  347.     }
  348.     else {           /* non-operator, non-numeric */
  349.       p = newnode();
  350.       strcpy(p->name,tok);
  351.       p->kind = VAR;
  352.       p->nump = 0;
  353.       push(p);
  354.     }
  355.     if (!tos->msg && *txt) {           /* Attach txt to the tos node */
  356.       tos->msg = malloc(strlen(txt)+1);
  357.       strcpy(tos->msg,txt);
  358.       *txt = 0;
  359.     }
  360.     else if (!tos->msg && tos->nump) {    /* move txt up from left child */
  361.       tos->msg = tos->parm[0]->msg;
  362.       tos->parm[0]->msg = NULL;
  363.     }
  364.   }
  365.   fclose(f);
  366.   return tos;
  367. }
  368.  
  369. /*-----------------------------------------------------------------
  370.    loadfile
  371. */
  372. void loadfile(char *fn) {
  373.   node *p; char s[160];
  374.   if (!fn || !*fn) return;
  375.   if (!strchr(fn+max(strlen(fn)-4,0),'.')) {
  376.     strcpy(s,fn); fn=s; strcat(s,".ae");
  377.   }
  378.   if (postfix) p=load(fn);
  379.   else p=loadinfix(fn);
  380.   if (firf) curf = lastnode(firf)->next = reverse(p);
  381.   else curf = firf = reverse(p);
  382. }
  383. /*-----------------------------------------------------------------
  384.    fprinttree
  385. */
  386. void fprinttree(FILE *f,node *p) {
  387.   int i;
  388.  
  389.   for (i=0; i<p->nump; ++i)
  390.     fprinttree(f,p->parm[i]);
  391.  
  392.   switch (p->kind) {
  393.     case NUM: if (p->value==M_PI) fprintf(f,"pi");
  394.               else if (p->value==M_E) fprintf(f,"e");
  395.               else fprintf(f," %1.16G",p->value); break;
  396.     case EQU: fprintf(f," ="); break;
  397.     case FUN: fprintf(f," %d @%s",p->nump,p->name); break;
  398.     case ADD: fprintf(f," +"); break;
  399.     case SUB: fprintf(f," -"); break;
  400.     case MUL: fprintf(f," *"); break;
  401.     case DIV: fprintf(f," /"); break;
  402.     case EXP: fprintf(f," ^"); break;
  403.     case VAR: fprintf(f," %s",p->name); break;
  404.     default: fprintf(f," ???"); break;
  405.   }
  406. }
  407. /*-----------------------------------------------------------------
  408.    putmsg - put message and convert \r to "
  409. */
  410. void putmsg(FILE *f,char *m) {
  411.   putc('"',f);
  412.   while (*m) {
  413.     if (*m!='\r') putc(*m,f);
  414.     else if (m[1]) putc('"',f);
  415.     ++m;
  416.   }
  417. }
  418.  
  419. /*-----------------------------------------------------------------
  420.    savefile
  421. */
  422. void savefile(char *fn) {
  423.   node *p;
  424.   FILE *f;
  425.   time_t t;
  426.  
  427.   f = fopen(fn,"w");
  428.   if (!f) {
  429.     printf(msg[9],fn);
  430.     pause;  return;
  431.   }
  432.   time(&t);
  433.   fprintf(f,msg[10],fn,ctime(&t));
  434.   p = firf;
  435.   while (p) {
  436.     if (p->msg) putmsg(f,p->msg);
  437.     else fprintf(f,";\n");
  438.     fprinttree(f,p);
  439.     fprintf(f,"\n");
  440.     p = p->next;
  441.   }
  442.   fclose(f);
  443. }
  444.  
  445. /*-----------------------------------------------------------------
  446.    fwritetree           = f + - * / ^ V N
  447.    precedence values:   0 8 2 2 4 4 6 8 8
  448. */
  449. void fwritetree(FILE *f,node *p,int pr) {
  450.   int i;
  451.  
  452.   if (pr > wpr[p->kind]) fprintf(f,"(");
  453.   switch (p->kind) {
  454.     case NUM: if (p->value==M_PI) fprintf(f,"pi");
  455.               else if (p->value==M_E) fprintf(f,"e");
  456.               else if (p->value<0 && stoe) fprintf(f,"(%1.16G)",p->value);
  457.               else fprintf(f,"%1.16G",p->value); break;
  458.     case EQU:
  459.       fwritetree(f,p->lf,0);
  460.       fprintf(f," = ");
  461.       fwritetree(f,p->rt,0); break;
  462.     case FUN:
  463.       fprintf(f,"%s(",p->name);
  464.       for (i=0; i<p->nump; ++i) {
  465.         fwritetree(f,p->parm[i],0);
  466.         if (i<p->nump-1) fprintf(f,",");
  467.       }
  468.       fprintf(f,")");
  469.       break;
  470.     case ADD:
  471.       fwritetree(f,p->lf,2);
  472.       fprintf(f," + ");
  473.       fwritetree(f,p->rt,3); break;
  474.     case SUB:
  475.       fwritetree(f,p->lf,2);
  476.       fprintf(f," - ");
  477.       fwritetree(f,p->rt,3); break;
  478.     case MUL:
  479.       fwritetree(f,p->lf,4);
  480.       fprintf(f,"*");
  481.       fwritetree(f,p->rt,5); break;
  482.     case DIV:
  483.       fwritetree(f,p->lf,4);
  484.       fprintf(f,"/");
  485.       fwritetree(f,p->rt,5); break;
  486.     case EXP:
  487.       fwritetree(f,p->lf,7);
  488.       fprintf(f,"^");
  489.       fwritetree(f,p->rt,6); break;
  490.     case VAR: fprintf(f,"%s",p->name); break;
  491.     default: fprintf(f,"???"); break;
  492.   }
  493.   if (pr > wpr[p->kind]) fprintf(f,")");
  494.   stoe = 0;
  495. }
  496. /*-----------------------------------------------------------------
  497.    writefile  this writes the file using infix notation.
  498.    I had to add the stoe flag so that when the first thing in an
  499.    expression is a negative number it will get parens around
  500.    it.  Otherwise it gets treated as a minus and glued to the former
  501.    expression.
  502. */
  503. void writefile(char *fn) {
  504.   node *p;
  505.   FILE *f;
  506.   time_t t;
  507.  
  508.   f = fopen(fn,"w");
  509.   if (!f) {
  510.     printf(msg[9],fn);
  511.     pause;  return;
  512.   }
  513.   time(&t);
  514.   fprintf(f,msg[11],fn,ctime(&t));
  515.   p = firf;
  516.   while (p) {
  517.     if (p->msg) putmsg(f,p->msg);
  518.     stoe=1;                 // start of expression
  519.     fwritetree(f,p,0);
  520.     fprintf(f,"\n");
  521.     p = p->next;
  522.   }
  523.   fclose(f);
  524. }
  525.